#include "ee_screenshot.h"
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtDebug>
#include <QtCore/QTime>

#ifdef Q_WS_WIN
	#include <windows.h>
#endif


struct EE_Screenshot::Data
{
#ifdef Q_WS_WIN
	int w, h;
	HDC display_dc, bitmap_dc;
	HBITMAP bitmap;
	HGDIOBJ null_bitmap;
	QImage image;
	Data()
	{
		w = 0;
		h = 0;
		adjustDimensions();
	}
	~Data()
	{
		cleanup();
	}
	void adjustDimensions()
	{
		int _w = ::GetSystemMetrics(SM_CXSCREEN);
		int	_h = ::GetSystemMetrics(SM_CYSCREEN);
		if ((w != _w) || (h != _h))
		{
			qDebug() << "EE_Screenshot is adjusting dimensions to" << _w << "x" << _h;
			if ((w > 0) && (h > 0))
			{
				cleanup();
			}
			w = _w; h = _h;
			image = QImage(w, h, QImage::Format_RGB32);
			init();
		}
	}
	void init()
	{
		display_dc = ::GetDC(0);
		bitmap_dc = ::CreateCompatibleDC(display_dc);
		bitmap = ::CreateCompatibleBitmap(display_dc, w, h);
	}
	void cleanup()
	{
		::DeleteDC(bitmap_dc);
		::DeleteObject(bitmap);
		::ReleaseDC(0, display_dc);
	}
	const QImage & take()
	{
		adjustDimensions();
		null_bitmap = ::SelectObject(bitmap_dc, bitmap);
		::BitBlt(bitmap_dc, 0, 0, w, h, display_dc, 0, 0, SRCCOPY);
		::SelectObject(bitmap_dc, null_bitmap);

		BITMAPINFO _bmi;
		::memset(&_bmi, 0, sizeof(_bmi));
		_bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
		_bmi.bmiHeader.biWidth       = w;
		_bmi.bmiHeader.biHeight      = -h;
		_bmi.bmiHeader.biPlanes      = 1;
		_bmi.bmiHeader.biBitCount    = 32;
		_bmi.bmiHeader.biCompression = BI_RGB;
		_bmi.bmiHeader.biSizeImage   = w * h * sizeof(int);

		QTime _time_start = QTime::currentTime();
		::GetDIBits(display_dc, bitmap, 0, h, (uchar *)image.bits(), &_bmi, DIB_RGB_COLORS);
		qDebug() << "GetDIBits time is" << _time_start.msecsTo(QTime::currentTime());
		return image;
	}

#else
	Data()
	{

	}
	const QImage & take()
	{
		return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
	}
#endif
};

EE_Screenshot::EE_Screenshot(): d(new Data())
{
}

EE_Screenshot::~EE_Screenshot()
{
	delete d;
}

const QImage & EE_Screenshot::take()
{
	return d->take();
}
